package jee.boot.module.authority.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jee.boot.common.basic.CrudService;
import jee.boot.common.basic.DataEntity;
import jee.boot.entity.system.Filter;
import jee.boot.common.standard.AuthorityHandler;
import jee.boot.common.utils.MapUtils;
import jee.boot.common.utils.StringUtils;
import jee.boot.entity.auth.*;
import jee.boot.module.authority.dao.AuthEntityDao;
import jee.boot.module.authority.dao.RowSetItemDao;
import jee.boot.entity.auth.AuthConstant;
import jee.boot.entity.system.TreeNode;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class AuthEntityService extends CrudService<AuthEntityDao, AuthEntity> {
    @Autowired
    private ResourceService resourceService;

    @Autowired
    private ModelDataService modelDataService;
    @Autowired
    private ColumnService columnService;
    @Autowired
    private RowSetService rowSetService;
    @Autowired
    private CellSetService cellSetService;
    @Autowired
    private RowSetItemDao rowSetItemDao;

    @Override
    public AuthEntity get(AuthEntity entity) {
        AuthEntity authEntity = super.get(entity);
        resetEntity(entity, new Authority(), new ArrayList<AuthEntity>() {{
            add(authEntity);
        }});
        return authEntity;
    }

    @Override
    public List<AuthEntity> findList(AuthEntity entity) {
        List<AuthEntity> list = super.findList(entity);
        resetEntity(entity, new Authority(), list);
        return list;
    }

    /**
     * 重置AuthEntity中的entity数据,根据entityId查询出来具体的entity回填到AuthEntity中
     *
     * @param authEntity
     * @param entity
     * @param list
     */
    public void resetEntity(AuthEntity authEntity, Authority entity, List<AuthEntity> list) {
        if (list.size() > 0) {
            // 设置资源
            List<AuthEntity> authResourceList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_RESOURCE, list);
            if (authResourceList != null && !authResourceList.isEmpty()) {
                Resource resource = new Resource();
                resource.addFilter(new Filter("id", "in", authResourceList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).map(d -> d.getEntityId()).collect(Collectors.toList())));
                List<Resource> resourceList = resourceService.findList(resource);
                backFillData(resourceList, authResourceList, list);
                entity.setResourceList(authResourceList);
            }
            // 设置树节点
            List<AuthEntity> authTreeNodeList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_TREE_NODE, list);
            if (authTreeNodeList != null && !authTreeNodeList.isEmpty()) {
                TreeNode treeNode = new TreeNode();
                treeNode.addFilter(new Filter("id", "in", authTreeNodeList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).map(d -> d.getEntityId()).collect(Collectors.toList())));
                List<TreeNode> treeNodeList = remoteEndpoint.executePost(projectConfig.getOpenSystemServer(),"/treeNode/all",treeNode,TreeNode.class);
                backFillData(treeNodeList, authTreeNodeList, list);
                entity.setTreeNodeList(authTreeNodeList);
            }
            // 设置Model
            List<AuthEntity> authModelList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_MODEL, list);
            if (authModelList != null && !authModelList.isEmpty()) {
                ModelData modelData = new ModelData();
                modelData.addFilter(new Filter("id", "in", authModelList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).map(d -> d.getEntityId()).collect(Collectors.toList())));
                List<ModelData> modelList = modelDataService.findList(modelData);
                backFillData(modelList, authModelList, list);
                entity.setModelList(authModelList);
            }
            // 设置Column
            List<AuthEntity> authColumnList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_COLUMN, list);
            if (authColumnList != null && !authColumnList.isEmpty()) {
                Column column = new Column();
                column.addFilter(new Filter("id", "in", authColumnList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).map(d -> d.getEntityId()).collect(Collectors.toList())));
                List<Column> columnList = columnService.findList(column);
                backFillData(columnList, authColumnList, list);
                sort(authColumnList);
                sort(list);
                entity.setColumnList(authColumnList);
            }
            // 设置RowSet
            List<AuthEntity> authRowSetList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_ROW_SET, list);
            if (authRowSetList != null && !authRowSetList.isEmpty()) {
                List<RowSet> rowSets = getRowSetList(authRowSetList);
                if (!rowSets.isEmpty()) {
                    backFillData(rowSets, authRowSetList, list);
                }
                entity.setRowSetList(authRowSetList);
            }
            // 设置CellSet
            List<AuthEntity> authCellSetList = getBasicObjIdListByType(AuthConstant.AUTH_ENTITY_TYPE_CELL_SET, list);
            if (authCellSetList != null && !authCellSetList.isEmpty()) {
                CellSet cellSet = new CellSet();
                cellSet.addFilter(new Filter("id", "in", authCellSetList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).map(d -> d.getEntityId()).collect(Collectors.toList())));
                List<CellSet> cellList = cellSetService.findList(cellSet);
                backFillData(cellList, authCellSetList, list);
                entity.setColumnList(authCellSetList);
            }

        }
    }

    public List<RowSet> getRowSetList(List<AuthEntity> authRowSetList) {
        RowSet rowSet = new RowSet();
        List<AuthEntity> collect = authRowSetList.stream().filter(d -> StringUtils.isNotBlank(d.getEntityId())).collect(Collectors.toList());
        if (collect != null && !collect.isEmpty()) {
            Map<String, AuthEntity> tempMap = Maps.newHashMap();
            for (AuthEntity tempAuth : collect) {
                tempMap.put(tempAuth.getEntityId(), tempAuth);
            }
            rowSet.addFilter(new Filter("id", "in", collect.stream().map(d -> d.getEntityId()).collect(Collectors.toList())));
            List<RowSet> rowSetList = rowSetService.findList(rowSet);
            if (!rowSetList.isEmpty()) {
                for (RowSet row : rowSetList) {
                    AuthEntity temp = tempMap.get(row.getId());
                    RowSetItem rowSetItem = new RowSetItem();
                    rowSetItem.setHeader(row);
                    rowSetItem.addFilter(new Filter("a.st_entity_type", "=", "DIC_AUTH_CtrledEntityType_CET05"));
                    rowSetItem.addFilter(new Filter("a.st_control_domain_id", "=", temp.getControlDomain().getId()));
                    rowSetItem.addFilter(new Filter("a.st_control_domain_type", "=", temp.getControlDomainType()));
                    rowSetItem.addFilter(new Filter("a.st_authority_id", "=", temp.getAuthority().getId()));
                    rowSetItem.addFilter(new Filter("a.st_model_id", "=", temp.getModelData().getId()));

                    List<RowSetItem> list1 = rowSetItemDao.findList(rowSetItem);
                    row.setItemList(list1);
                }
            }
            return rowSetList;
        }
        return Lists.newArrayList();
    }

    @Caching(evict = {
            @CacheEvict(value = AuthorityHandler.USER_AUTHORITY_KEY, allEntries = true)
    })
    @Override
    public void save(AuthEntity entity) {
        //RowSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_ROW_SET, entity.getEntityType())) {
            RowSet rowSet = MapUtils.toBean(entity.getEntity(), RowSet.class);//JsonMapper.fromJsonString(JsonMapper.toJsonString(entity.getEntity()), RowSet.class);
            rowSetService.save(rowSet);
            entity.setEntityId(rowSet.getId());
        }
        //CellSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_CELL_SET, entity.getEntityType())) {
            CellSet cellSet = MapUtils.toBean(entity.getEntity(), CellSet.class);//JsonMapper.fromJsonString(JsonMapper.toJsonString(entity.getEntity()), CellSet.class);
            cellSetService.save(cellSet);
            entity.setEntityId(cellSet.getId());
        }
        super.save(entity);
    }

    @Caching(evict = {
            @CacheEvict(value = AuthorityHandler.USER_AUTHORITY_KEY, allEntries = true)
    })
    @Override
    public void update(AuthEntity entity) {
        //RowSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_ROW_SET, entity.getEntityType())) {
            RowSet rowSet = MapUtils.toBean(entity.getEntity(), RowSet.class);//JsonMapper.fromJsonString(JsonMapper.toJsonString(entity.getEntity()), RowSet.class);
            rowSetService.update(rowSet);
        }
        //CellSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_CELL_SET, entity.getEntityType())) {
            CellSet cellSet = MapUtils.toBean(entity.getEntity(), CellSet.class);//JsonMapper.fromJsonString(JsonMapper.toJsonString(entity.getEntity()), CellSet.class);
            cellSetService.update(cellSet);
        }
        super.update(entity);
    }

    @Caching(evict = {
            @CacheEvict(value = AuthorityHandler.USER_AUTHORITY_KEY, allEntries = true)
    })
    @Override
    public void delete(AuthEntity entity) {
        entity = super.get(entity);
        //RowSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_ROW_SET, entity.getEntityType())) {
            rowSetService.delete(new RowSet(entity.getEntityId()));
        }
        //CellSet类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_CELL_SET, entity.getEntityType())) {
            cellSetService.delete(new CellSet(entity.getEntityId()));
        }
        //ModelData类型的数据
        if (StringUtils.equals(AuthConstant.AUTH_ENTITY_TYPE_MODEL, entity.getEntityType())) {
            AuthEntity del = new AuthEntity();
            del.setAuthority(entity.getAuthority());
            del.setModelData(new ModelData(entity.getEntityId()));
            del.setControlDomainType(entity.getControlDomainType());
            del.setControlDomain(entity.getControlDomain());
            // 删除RowSet实体数据
            deleteRowSetByAuthEntity(del);
            // 删除CellSet实体数据
            deleteCellSetByAuthEntity(del);
            // 删除所有的与model有关的关系数据
            dao.deleteByAuthEntity(del);
        }
        super.delete(entity);
    }

    @Caching(evict = {
            @CacheEvict(value = AuthorityHandler.USER_AUTHORITY_KEY, allEntries = true)
    })
    @Override
    public void batchUpdate(List<AuthEntity> list) {
        super.batchUpdate(list);
    }


    /**
     * 回填客体数据到关联表信息中
     *
     * @param entityList
     * @param authEntityList
     * @param list
     */
    public void backFillData(List<? extends DataEntity> entityList, List<AuthEntity> authEntityList, List<AuthEntity> list) {
        Map<String, DataEntity> tempMap = Maps.newHashMap();
        if (entityList != null) {
            entityList.forEach(d -> {
                tempMap.put(d.getId(), d);
            });
        }
        authEntityList.forEach(d -> {
            d.setEntity(tempMap.get(d.getEntityId()));
        });
        List<AuthEntity> delList = Lists.newArrayList();
        // 未关联到的entity需要被移除关系
        Iterator<AuthEntity> iterator = authEntityList.iterator();
        while (iterator.hasNext()) {
            AuthEntity next = iterator.next();
            if (next.getEntity() == null) {
                delList.add(next);
            }
        }
        if (!delList.isEmpty()) {
            delList.forEach(del -> {
                authEntityList.remove(del);
                list.remove(del);
            });
        }

    }
    private void sort(List<AuthEntity> authEntityList){
        //冒泡排序算法
        //需进行length-1次冒泡
        for(int i=0;i<authEntityList.size()-1;i++)
        {
            for(int j=0;j<authEntityList.size()-1-i;j++)
            {
                AuthEntity entityJ = authEntityList.get(j);
                AuthEntity entityJ1 = authEntityList.get(j+1);
                Integer sortJ=entityJ.getDefSort();
                Integer sortJ1=entityJ1.getDefSort();
                try{
                    Integer a = (Integer) PropertyUtils.getProperty(entityJ.getEntity(), "sort");
                    if(a!=null){
                        sortJ=a;
                    }
                }catch (Exception e){}
                try{
                    Integer a =  (Integer) PropertyUtils.getProperty(entityJ1.getEntity(), "sort");
                    if(a!=null){
                        sortJ1=a;
                    }
                }catch (Exception e){}

                if(sortJ>sortJ1)
                {
                    AuthEntity temp=authEntityList.get(j);
                    authEntityList.set(j,authEntityList.get(j+1));
                    authEntityList.set(j+1,temp);
                }
            }
        }

//        // 排序-这样写有时候会报错,还是换成手动写的冒泡排序吧
//        Collections.sort(authEntityList, new Comparator<AuthEntity>() {
//            @Override
//            public int compare(AuthEntity o1, AuthEntity o2) {
//                try {
//                    Integer sort1 = (Integer) PropertyUtils.getProperty(o1.getEntity(), "sort");
//                    Integer sort2 = (Integer) PropertyUtils.getProperty(o2.getEntity(), "sort");
//                    return sort1 .compareTo(sort2) ;
//                } catch (Exception e) {
//                    return o1.getDefSort().compareTo(o2.getDefSort());
//                }
//            }
//        });
    }
    /**
     * 根据关联表的数据按类型取出所有的权限实体entity的id
     *
     * @param type
     * @param list
     * @return
     */
    public List<AuthEntity> getBasicObjIdListByType(String type, List<AuthEntity> list) {
        return list.stream()
                .filter(d -> StringUtils.equals(type, d.getEntityType()))
                .collect(Collectors.toList());
    }

    /**
     * 根据关联关系删除RowSet,RowSetItem,CellSet数据
     *
     * @param entity
     */
    public void deleteEntityByAuthEntity(AuthEntity entity) {
        // 删除RowSet(连带RowSetItem)
        deleteRowSetByAuthEntity(entity);
        // 删除CellSet
        deleteCellSetByAuthEntity(entity);
    }

    private void deleteCellSetByAuthEntity(AuthEntity entity) {
        AuthEntity query = new AuthEntity();
        query.addFilter(new Filter("authority", "=", entity.getAuthority().getId()));
        query.addFilter(new Filter("entityType", "=", AuthConstant.AUTH_ENTITY_TYPE_CELL_SET));
        if (StringUtils.isNotBlank(entity.getControlDomainType())) {
            query.addFilter(new Filter("controlDomainType", "=", entity.getControlDomainType()));
        }
        if (StringUtils.isNotBlank(entity.getControlDomain().getId())) {
            query.addFilter(new Filter("controlDomain.id", "=", entity.getControlDomain().getId()));
        }
        if (entity.getModelData() != null && StringUtils.isNotBlank(entity.getModelData().getId())) {
            query.addFilter(new Filter("modelData", "=", entity.getModelData().getId()));
        }
        List<AuthEntity> list = findList(query);
        if (list != null && !list.isEmpty()) {
            for (AuthEntity authEntity : list) {
                cellSetService.delete(new CellSet(authEntity.getEntityId()));
            }
        }
    }

    private void deleteRowSetByAuthEntity(AuthEntity entity) {
        AuthEntity query = new AuthEntity();
        query.addFilter(new Filter("authority", "=", entity.getAuthority().getId()));
        query.addFilter(new Filter("entityType", "=", AuthConstant.AUTH_ENTITY_TYPE_ROW_SET));
        if (StringUtils.isNotBlank(entity.getControlDomainType())) {
            query.addFilter(new Filter("controlDomainType", "=", entity.getControlDomainType()));
        }
        if (StringUtils.isNotBlank(entity.getControlDomain().getId())) {
            query.addFilter(new Filter("controlDomain.id", "=", entity.getControlDomain().getId()));
        }
        if (entity.getModelData() != null && StringUtils.isNotBlank(entity.getModelData().getId())) {
            query.addFilter(new Filter("modelData", "=", entity.getModelData().getId()));
        }
        List<AuthEntity> list = findList(query);
        if (list != null && !list.isEmpty()) {
            for (AuthEntity authEntity : list) {
                rowSetService.delete(new RowSet(authEntity.getEntityId()));
            }
        }

    }

}
